/**
 * @file 应用程序实现文件
 *
 * 应用程序全局范围定义实现
 *
 * @author wq1977@gmail.com
 */


#include "wx/intl.h"
#include <wx/cmdline.h>
#include "app.h"
#include "ScenariosForm.h"
#include "OsipProcess.h"
#include <wx/wfstream.h>
#include "wx/numdlg.h"
#include "wx/image.h"
#include "wx/splash.h"
#include "version.h"

#include "../bitmaps/new.xpm"
#include "../bitmaps/open.xpm"
#include "../bitmaps/save.xpm"
#include "../bitmaps/copy.xpm"
#include "../bitmaps/cut.xpm"
#include "../bitmaps/paste.xpm"
#include "../bitmaps/print.xpm"
#include "../bitmaps/help.xpm"

DEFINE_EVENT_TYPE(wxEVT_SCENARIO_EXIT)

IMPLEMENT_CLASS(UidwxStringPair,wxObject);
IMPLEMENT_CLASS(TimerStru,wxObject);
IMPLEMENT_CLASS(wxMyEqual,wxObject);
IMPLEMENT_CLASS(SipRawMsg,wxObject);
IMPLEMENT_CLASS(SipRawEventQueue,wxObject);

class MyEvtHandler : public wxEvtHandler
{
public:
    void OnCloseWindow(wxCloseEvent& event);
protected:
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler)
    EVT_CLOSE(MyEvtHandler::OnCloseWindow)
END_EVENT_TABLE()


wxGauge* splashgauge=NULL;
wxStaticText *splashtext=NULL;
bool redirecttrace=false;

void MyEvtHandler::OnCloseWindow(wxCloseEvent& event){
    splashgauge=NULL;
    splashtext=NULL;
    event.Skip();
}

/*
class MyDebugReport : public wxDebugReportCompress
{
public:
    virtual bool DoProcess()
    {
        if ( !wxDebugReportCompress::DoProcess() )
            return false;

	wxString mailto=_("mailto:cnwesleywang@gmail.com?subject=coredump file&body=Please Attach file ")+GetCompressedFileName();
#ifdef WIN32
	ShellExecute(NULL, wxT("open"), mailto, wxT(""), NULL, SW_SHOWNORMAL);
#endif

	return true;//wxCopyFile(GetCompressedFileName(), CoreFile, true);
    }
};
*/

BEGIN_EVENT_TABLE(MyFrame, wxMDIParentFrame)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
//    EVT_MENU(Minimal_Close,  MyFrame::OnClose)
    EVT_MENU(Minimal_Clear_Trace,  MyFrame::OnClearTrace)
    EVT_MENU(Minimal_Clear_Statistic,  MyFrame::OnClearStatictic)
    EVT_MENU(Minimal_Clear_Timer,  MyFrame::OnClearTimer)
    EVT_MENU(Minimal_Clear_Transaction,  MyFrame::OnClearTrans)
    EVT_MENU(Minimal_Force_Port,  MyFrame::OnForcePort)
    EVT_MENU(Minimal_Update_AllCase,  MyFrame::OnUpdateAllCase)
    EVT_MENU(Minimal_GLOBAL_LANGUAGE_CHOOSE_CHINESE,  MyFrame::OnLangChinese)
    EVT_MENU(Minimal_GLOBAL_LANGUAGE_CHOOSE_ENGLISH,  MyFrame::OnLangEnglish)
    EVT_MENU(Minimal_About, MyFrame::OnAbout)
    EVT_MENU(Minimal_Conf, MyFrame::OnConfig)
    EVT_MENU(Minimal_CHANGE_IDENT, MyFrame::OnChangeIdent)
    EVT_MENU(MDI_NEW_WINDOW, MyFrame::OnNewWindow)
    EVT_CLOSE(MyFrame::OnClose)
    EVT_TIMER(STATUS_BAR_TIMER_ID, MyFrame::OnTimer)
//EVT_IDLE(MyFrame::OnIdle)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(ConfigDialog, wxDialog)
    EVT_BUTTON(-1, ConfigDialog::OnButton)
END_EVENT_TABLE()

IMPLEMENT_APP(MyApp)

bool bindflag=true;
extern int ForcePort;

void TransManager::ClearAllTrans(){
  wxMutexLocker lock(s_mutexProtectingTranses);
  for(TransValidHash::iterator iter = AllTranses.begin(); iter != AllTranses.end();)
    {
      TransValidHash::iterator qiter=iter;
      iter++;
      if (qiter->second){
	  osip_remove_transaction(wxGetApp().osip,(osip_transaction_t*)qiter->first);
	  osip_transaction_free2((osip_transaction_t*)qiter->first);
      }
    }
  AllTranses.clear();
}

void TransManager::FreeDeadTrans(){
  wxMutexLocker lock(s_mutexProtectingTranses);
  for(TransValidHash::iterator iter = AllTranses.begin(); iter != AllTranses.end();)
      {
	  TransValidHash::iterator qiter=iter;
	  iter++;
	  if (!qiter->second){
	      osip_remove_transaction(wxGetApp().osip,(osip_transaction_t*)qiter->first);
	      osip_transaction_free2((osip_transaction_t*)qiter->first);
	      wxGetApp().AllTranses.Erase(qiter,false);
	      NeedUpdate=true;
	  }
      }

}

void TransManager::AddTrans(osip_transaction_t *t){
  wxMutexLocker lock(s_mutexProtectingTranses);
  if (AllTranses.find(t) == AllTranses.end()){
    AllTranses[t] = true;
  }
}

void TransManager::RemoveTrans(osip_transaction_t *t, bool lock){
  if (IsAlive(t)){
	if (lock) wxMutexLocker lock(s_mutexProtectingTranses);
	printf("Remove Trans:%s\n",t->orig_request->sip_method);
      AllTranses[t] = false;
  }
}

bool TransManager::IsExists(osip_transaction_t *t){
    return AllTranses.find(t) != AllTranses.end();
}

bool TransManager::IsAlive(osip_transaction_t *t){
  return IsExists(t) && AllTranses[t];
}

void TransManager::Erase(TransValidHash::iterator iter, bool lock){
    if (lock) wxMutexLocker lock(s_mutexProtectingTranses);
    AllTranses.erase(iter);
};

void TransManager::DumpAll(){
  wxMutexLocker lock(s_mutexProtectingTranses);
  wxGetApp().DoLog(wxT("Dump All Transaction:\n"));
  for (TransValidHash::iterator iter=AllTranses.begin();iter!=AllTranses.end();iter++){
      wxGetApp().DoLog(wxString::Format(wxT("%p %u\n"),iter->first,iter->second));
  }
};

static wxMutex s_mutexProtectingTheTimerCb;
bool TimerThread::RequestTimer(int Uid,int TimerLen,wxString name,long id){
  wxMutexLocker lock(s_mutexProtectingTheTimerCb);
  TimerStru cb;
  cb.StartAt = wxDateTime::UNow();
  cb.TimerLen = TimerLen;
  cb.ident=id;
  UidwxStringPair stPair(Uid,name);
  /*stPair.Uid =Uid;
    stPair.name =name;*/

  if (AllTimerCb.find(stPair.ToString()) != AllTimerCb.end()) return false;
  AllTimerCb[stPair.ToString()]=cb;

  STT_TRACE(Uid,TL_MESSAGE,wxString::Format(wxT("New Timer Requested: %s %d"),name.c_str(),Uid));

  /*STT_TRACE(Uid,TL_MESSAGE,wxT("New Timer Requested:")+name);
  		  TimerCbHash::iterator iter;
		  for(iter = AllTimerCb.begin(); iter != AllTimerCb.end();) {
		    TimerCbHash::iterator qiter=iter;
		    STT_TRACE(qiter->first.Uid,TL_MESSAGE,wxString::Format(wxT("Got one Timer record:%d %d %s!!"),qiter->first.Uid,
									    qiter->second.TimerLen,qiter->first.name.c_str()));
		    // if ((*iter).second.StartAt<(now-wxTimeSpan(0,0,(*iter).second.TimerLen,0))){
		      //wxGetApp().DisPatchEvt((*iter).first.Uid, new SttEvt((*iter).first.name));
		      //AllTimerCb.erase(iter);
		    //}
		    iter++;
		    }*/

  return true;
}

bool TimerThread::CancelScenarioTimer(int ScenarioFormIndex){
  wxMutexLocker lock(s_mutexProtectingTheTimerCb);
  if (ScenarioFormIndex==-1){
      AllTimerCb.clear();
  }
  else{
      for (TimerCbHash::iterator iter=AllTimerCb.begin();
	   iter!=AllTimerCb.end();){
	  TimerCbHash::iterator qiter=iter;
	  iter++;
	  long Uid=-1;
	  qiter->first.BeforeFirst(wxT('|')).ToLong(&Uid);
	  int ScenarioId = Uid /MAX_TERM_NUM;
	  int ScenarioFormId = ScenarioId % MAX_SCENARIOS_NUM;
	  if (ScenarioFormId == ScenarioFormIndex){
	      AllTimerCb.erase(qiter);
	  }
      }
  }
  return true;
}

bool TimerThread::CancelTimer(wxString timer){
  wxMutexLocker lock(s_mutexProtectingTheTimerCb);
  TimerCbHash::iterator iter=AllTimerCb.find(timer);
  if (iter == AllTimerCb.end()) return false;
  AllTimerCb.erase(iter);
  return true;
}

bool TimerThread::CancelTimer(int Uid, wxString name){
  wxMutexLocker lock(s_mutexProtectingTheTimerCb);
  UidwxStringPair stPair(Uid,name);
  TimerCbHash::iterator iter=AllTimerCb.find(stPair.ToString());
  if (iter == AllTimerCb.end()) return false;
  AllTimerCb.erase(iter);
  return true;
}

extern wxString TimeToStr(wxDateTime start);
void TimerThread::DumpTimer(int Uid){
    wxMutexLocker lock(s_mutexProtectingTheTimerCb);
    STT_TRACE(Uid,TL_MESSAGE,wxString::Format(wxT("Start to Dump Timer!")));
    for (TimerCbHash::iterator iter=AllTimerCb.begin();
	 iter!=AllTimerCb.end();iter++){
	STT_TRACE(Uid,TL_MESSAGE,wxString::Format(wxT("Timer %s: StartAt:%s TimerLen:%d"),
						  iter->first.c_str(),
						  TimeToStr(iter->second.StartAt).c_str(),
						  iter->second.TimerLen));
    }
}

void *TimerThread::Entry(){
	while (true){

		{//Before Sleep, Let's release the mutex first!
		  wxMutexLocker lock(s_mutexProtectingTheTimerCb);
		  wxDateTime now = wxDateTime::UNow();

		  TimerCbHash::iterator iter;
		  for(iter = AllTimerCb.begin(); iter != AllTimerCb.end();) {
		    TimerCbHash::iterator qiter=iter;
		    iter++;
		    if ((*qiter).second.StartAt<(now-wxTimeSpan(0,0,(*qiter).second.TimerLen,0))){
			long Uid=-1;
			(*qiter).first.BeforeFirst(wxT('|')).ToLong(&Uid);
			SttEvt *e=new SttEvt(Uid,(*qiter).first.AfterFirst(wxT('|')));
			e->SetTimerIdent((*qiter).second.ident);
			wxGetApp().DisPatchEvt(Uid, e);
			AllTimerCb.erase(qiter);
		    }

		  }

		}
		if (wxGetApp().ApplicationExit){//Does someone ask to delete me?
		  break;
		}
		wxMilliSleep(200);
	}
	return NULL;
}

/**
  * Osip Poll 线程入口
  *
  * we believe that osip library is thread-safe,so we will not use Semaphore
  *
  */
void *OsipPollThread::Entry(){
    while (1){
      {
	  osip_ict_execute(osip);
	  osip_ist_execute(osip);
	  osip_nict_execute(osip);
	  osip_nist_execute(osip);
	  osip_timers_ict_execute(osip);
	  osip_timers_ist_execute(osip);
	  osip_timers_nict_execute(osip);
	  osip_timers_nist_execute(osip);
      }

      wxGetApp().AllTranses.FreeDeadTrans();

      if (wxGetApp().ApplicationExit){//Does someone ask to delete me?
	  break;
      }

      /*if (wxGetApp().AllTranses.NeedUpdate){
	  wxMutexLocker lock(wxGetApp().AllTranses.s_mutexProtectingTranses);
	  wxGetApp().AllTranses.NeedUpdate=false;
	  wxGetApp().IncStatisticItem(STT_OSIP_CURRENT_TRANS_NUM);
	  }*/
      wxMilliSleep(100);
    }
    return NULL;
}

bool MyApp::MyselfTooBusy(){
    return GetTotalTransInStack()>MaxTransNumInStack;
}

long MyApp::GetTotalTransInStack(){
    long ret=0;
    ret +=osip_list_size(osip->osip_ict_transactions)+
	osip_list_size(osip->osip_ist_transactions)+
	osip_list_size(osip->osip_nict_transactions)+
	osip_list_size(osip->osip_nist_transactions);
    return ret;
}

TermControl *MyApp::GetTermIns(int Uid){
    if (Uid != -1){
	int TermId=Uid %MAX_TERM_NUM;
	int ScenarioId = Uid /MAX_TERM_NUM;
	int ScenarioFormId = ScenarioId % MAX_SCENARIOS_NUM;
	int ScenarioSeq = ScenarioId / MAX_SCENARIOS_NUM;
	ScenariosForm *sf=AllScenariosForm[ScenarioFormId];
	if ((sf) && (sf->SeqId == ScenarioSeq)){
	    TermControl *tc=sf->GetTermCtrl(TermId);
	    if (tc){
		return tc;//->CallIdMatch(STT_LStr(callidstr.c_str()));
	    }
	}
    }
    return NULL;
}

bool MyApp::MatchCallId(int Uid, std::string callidstr,bool AllowAppend){
    TermControl *tc=GetTermIns(Uid);
    if (tc){
	return tc->CallIdMatch(STT_LStr(callidstr.c_str()),AllowAppend);
    }
    return false;
    /*	if (Uid != -1){
		int TermId=Uid %MAX_TERM_NUM;
		int ScenarioId = Uid /MAX_TERM_NUM;
		int ScenarioFormId = ScenarioId % MAX_SCENARIOS_NUM;
		int ScenarioSeq = ScenarioId / MAX_SCENARIOS_NUM;
		ScenariosForm *sf=AllScenariosForm[ScenarioFormId];
		if ((sf) && (sf->SeqId == ScenarioSeq)){
			TermControl *tc=sf->GetTermCtrl(TermId);
			if (tc){
				return tc->CallIdMatch(STT_LStr(callidstr.c_str()));
			}
		}
	}
	return false;*/
}

void MyApp::EraseFormIndex(ScenariosForm *form, int Index){
	if ((Index>=0) && (Index<MAX_SCENARIOS_NUM)){
		if (AllScenariosForm[Index] == form){
			AllScenariosForm[Index] = NULL;
			return;
		}
	}
	wxLogError(_("Bad Index Value or Form does not match!!"));
}

//! 全局事件分发函数
/*!
将事件pstevt分发在Uid终端所在的事件队列中
*/
void MyApp::DisPatchEvt(int Uid, SttEvt*pstevt){
	int ScenarioId = Uid /MAX_TERM_NUM;
	int ScenarioFormId = ScenarioId % MAX_SCENARIOS_NUM;
	int ScenarioSeq = ScenarioId / MAX_SCENARIOS_NUM;
	ScenariosForm *sf=AllScenariosForm[ScenarioFormId];
	STT_TRACE(Uid,TL_MESSAGE,_("Dispatch Event:")+
			  wxString::Format(wxT(" %d %d %d"),Uid,sf->SeqId,ScenarioSeq,pstevt->GetEvtType()));
	if ((sf) && (sf->SeqId == ScenarioSeq)){
		if (sf->m_ScenarioControl){
		    if (sf->m_ScenarioControl->AppendEvent(pstevt,Uid)){
			return;
		    }
		}
	}
	STT_TRACE(-1,TL_ERROR,_("Fail To Dispatch Event!!")+
		  wxString::Format(wxT(" %d %d %d"),Uid,sf->SeqId,ScenarioSeq));
	pstevt->Dump(-1);
	delete(pstevt);
}

void MyApp::CheckAndPoll(bool HasTrans){
    bool NeedPollStack=true;
    for (int i=0;i<MAX_SCENARIOS_NUM;i++){
	if (AllScenariosForm[i] && AllScenariosForm[i]->m_ScenarioControl){
	    NeedPollStack=false;//m_ScenarioControl will do that
	    break;
	}
    }

    if ((HasTrans) &&(NeedPollStack)){
	osip_ict_execute(wxGetApp().osip);
	osip_ist_execute(wxGetApp().osip);
	osip_nict_execute(wxGetApp().osip);
	osip_nist_execute(wxGetApp().osip);
	osip_timers_ict_execute(wxGetApp().osip);
	osip_timers_ist_execute(wxGetApp().osip);
	osip_timers_nict_execute(wxGetApp().osip);
	osip_timers_nist_execute(wxGetApp().osip);

	//Free Memory of dead transaction
	AllTranses.FreeDeadTrans();

    }
}

//Change The UI Update work to OnIdle
void MyFrame::OnTimer(wxTimerEvent& event)
//void MyFrame::OnIdle(wxIdleEvent& event)
{

    //Update Global Statistic
    long totaltrans=0;
    for (int Item=STT_MSG_TOTAL_SENT;Item<STT_STATISITEM_NUMS;Item++){
	SetStatusText(wxString::Format(wxT("%ld"),wxGetApp().AllStatistics[Item]),Item);
    }
    totaltrans+=osip_list_size(wxGetApp().osip->osip_ict_transactions);
    totaltrans+=osip_list_size(wxGetApp().osip->osip_ist_transactions);
    totaltrans+=osip_list_size(wxGetApp().osip->osip_nict_transactions);
    totaltrans+=osip_list_size(wxGetApp().osip->osip_nist_transactions);
    SetStatusText(wxString::Format(wxT("%ld"),totaltrans),STT_OSIP_CURRENT_TRANS_NUM);

    wxGetApp().CheckAndPoll(totaltrans>0);

    // 进行空闲事件处理,如果没有处理完
    // 再次请求空闲事件
    /*if (!FinishedIdleTask())
      event.RequestMore();*/
    event.Skip();
}

void MyApp::IncStatisticItem(int Item){
    if (Item<STT_STATISITEM_NUMS){
	AllStatistics[Item]++;
    }
}

void MyApp::Trace(int Level,const wxString& Value){
  if (ApplicationExit) return;
	m_traceForm->Trace(Level,Value,false);
}

int MyApp::GetFormIndex(ScenariosForm * f){
	for (int i=0;i<MAX_SCENARIOS_NUM;i++){
		if (f==AllScenariosForm[i]) return i;
	}
	return -1;
}

void MyApp::Trace(int Uid, int Level,const wxString& Value){
    if (redirecttrace){
        DoLog(Value);
        return;
    }
//  printf("%d %d:%s\n",Uid,Level,Value.c_str());
//  return;

  if (ApplicationExit) return;
  if (!frame) return;
  if (!frame->gtMenu) return;
	if (Uid != -1){
		int TermId=Uid %MAX_TERM_NUM;
		int ScenarioId = Uid /MAX_TERM_NUM;
		int ScenarioFormId = ScenarioId % MAX_SCENARIOS_NUM;
		int ScenarioSeq = ScenarioId / MAX_SCENARIOS_NUM;
		ScenariosForm *sf=AllScenariosForm[ScenarioFormId];
		if ((sf) && (sf->SeqId == ScenarioSeq)){
		  if (sf->m_ScenariosControlPanel->IsTraceEnable(Level)){
		    TermControl *tc=sf->GetTermCtrl(TermId);
		    if (tc){
		      tc->Trace(Level, Value);
		      return;
		    }
		  }
		  else{
		    return;
		  }
		}
	}
	switch (Level){
	case TL_SIP_MESSAGE:
	case TL_MESSAGE_RETRANS:
	  if ((frame)&&(frame->gtMenu)&&(!frame->gtMenu->IsChecked(Minimal_GLOBAL_TRACE_SIP))) return;
	  break;
	default:
	  if ((frame)&&(frame->gtMenu)&& (!frame->gtMenu->IsChecked(Minimal_GLOBAL_TRACE_INFO))) return;
	  break;
	}
	m_traceForm->Trace(Level,Value);
}

void MyApp::InitGlobalConfig(){
  /*typedef struct{
		wxString key;
		wxString Value;
	}KeyValuePair;
	KeyValuePair AllKeyValue[]={
		{_("Proxy_Address"),wxT("127.0.0.1")},
	};
	wxConfigBase *pConfig = wxConfigBase::Get();
	pConfig->SetPath(GLOBAL_KEY);
	for (size_t i=0; i<sizeof(AllKeyValue)/sizeof(KeyValuePair);i++){
		if (!pConfig->HasEntry(AllKeyValue[i].key)){
			pConfig->Write(AllKeyValue[i].key,AllKeyValue[i].Value);
		}
		}*/
}

static const wxCmdLineEntryDesc cmdLineDesc[] =
{
    { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _("show this help message"),
        wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
    { wxCMD_LINE_SWITCH, _T("n"), _T("nobind"), _("not bind the send sock port") },
    { wxCMD_LINE_SWITCH, NULL, _T("nomd5"), _("do not use md5 even MD5 gives in the sip message") },
    { wxCMD_LINE_OPTION, NULL, wxT("term-num"), _("Specify the TermNum") },
    { wxCMD_LINE_OPTION, NULL, wxT("call-times"), _("Specify the call times") },
    { wxCMD_LINE_OPTION, NULL, wxT("call-durtion"), _("Specify the call durtion") },
    { wxCMD_LINE_OPTION, NULL, wxT("call-hold"), _("not used so far") },
    { wxCMD_LINE_OPTION, NULL, wxT("call-heavy"), _("Specify the call heavy") },
    { wxCMD_LINE_OPTION, NULL, wxT("scenario"), _("Specify the scenario") },
    { wxCMD_LINE_OPTION, NULL, _T("redirecttrace"), wxT("Redirect Trace to Log file.") },

    { wxCMD_LINE_SWITCH, NULL, _T("nosplash"), _("switch off the splash") },
    { wxCMD_LINE_SWITCH, NULL, _T("fixedtest"), wxT("") },
    { wxCMD_LINE_SWITCH, NULL, _T("roundtest"), wxT("") },
    { wxCMD_LINE_SWITCH, NULL, _T("randomtest"), wxT("") },
    { wxCMD_LINE_SWITCH, NULL, _T("finalnever"), wxT("") },
    { wxCMD_LINE_SWITCH, NULL, _T("finalscefinish"), wxT("") },
    { wxCMD_LINE_SWITCH, NULL, _T("finalcasefinish"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("tracedebug"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("tracesip"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("traceerror"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("stoponfail"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("safestop"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("tracetermstate"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("forceport"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("daemon"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("checkinstance"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("reportpath"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("lastformindex"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("memlimit"), wxT("") },
    { wxCMD_LINE_OPTION, NULL, _T("maxtransinstack"), wxT("") },

    { wxCMD_LINE_NONE }
};

bool MyApp::NeedStopForMemNotEnough(){
    if (FreeMemWhenInit<0) return false;
    wxMemorySize nowfree=wxGetFreeMemory();
    if (nowfree<0) return false;
    return (nowfree<(double)FreeMemWhenInit * 0.4);
}

long ScenariosFormSeq=1;
long lastformindex=0;

bool MyApp::OnInit()
{

    NoMd5=false;

    wxLog::SetActiveTarget(new wxLogStderr());
    m_locale.Init(/*wxLANGUAGE_CHINESE_SIMPLIFIED*/);
    wxLocale::AddCatalogLookupPathPrefix(wxT("."));
    wxLocale::AddCatalogLookupPathPrefix(wxT(".."));
    m_locale.AddCatalog (wxT("SipTestTool"));

    wxImage::AddHandler(new wxPNGHandler);

    MaxTransNumInStack=500;

    for (int i=0;i<argc;i++){
	DoLog(wxString(argv[i])+wxT(" "));
    }

    ReportPath=wxT("");
    bool CmdLineParsed=false;
    bool CheckInstance=true;
    bool nosplash=false;
    wxCmdLineParser parser(cmdLineDesc, argc, argv);
    if (parser.Parse() ==0){
	CmdLineParsed=true;
	if (parser.Found(wxT("n"))){
	    bindflag=false;
	}
	if (parser.Found(wxT("nosplash"))){
	    nosplash=true;
	}
	wxString v;
	if (parser.Found(wxT("checkinstance"),&v)){
	    CheckInstance = (!(v==wxT("no")));
	}
    }
    m_checker = new wxSingleInstanceChecker(wxT("SipTestTool"));
    if (CheckInstance){
	if ( m_checker->IsAnotherRunning() ){
	    wxLogError(_("You can only run one instance of SipTestTool!"));
	    return false;
	}
    }
    m_server = new stServer;
    if (!m_server->Create(wxT("8677"))) {
	wxLogDebug(_("Failed to create an IPC service."));
	delete(m_checker);
	return false;
    }
    MaxTimerNum=0;

    if (!nosplash){
	wxBitmap bitmap;
	if (bitmap.LoadFile(_T("splash.png"), wxBITMAP_TYPE_PNG)) {
	    wxSplashScreen*splash=new wxSplashScreen(bitmap,
						     wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
						     6000, NULL, wxID_ANY, wxDefaultPosition, wxDefaultSize,
						     wxSIMPLE_BORDER|wxSTAY_ON_TOP);
	    wxWindow *win = splash->GetSplashWindow();

	    MyEvtHandler *h=new MyEvtHandler();
	    splash->PushEventHandler(h);

	    wxStaticText *text = new wxStaticText( win, wxID_EXIT, wxString(_("Version:"))+wxT(STT_VERSION), wxPoint(420,50),wxSize(200,50));
	    text->SetBackgroundColour(*wxWHITE);
	    text->SetForegroundColour(*wxBLACK);
	    wxFont font = text->GetFont();
	    font.SetPointSize(5*font.GetPointSize()/3);
	    text->SetFont(font);

	    splashgauge= new wxGauge(win, wxID_ANY, 104, wxPoint(10,100), wxSize(300,20), wxGA_HORIZONTAL);
	    splashtext=new wxStaticText( win, wxID_ANY, wxT(""), wxPoint(10,130));
	    splashtext->SetBackgroundColour(*wxWHITE);
	    splashtext->SetForegroundColour(*wxBLACK);

	}
	wxYield();
    }

    /*
    FreeMemWhenInit = wxGetFreeMemory();
    if (FreeMemWhenInit>0){
	wxGetApp().DoLog(wxString::Format(_("All the Case will stop when the system free memory is not more than %ld"),(long)((double)FreeMemWhenInit*0.4)));
    }
    */

#ifndef WIN32
    //wxHandleFatalExceptions();
#endif

    ApplicationExit=false;
    frame=NULL;
#ifdef __WIN32__
    WSADATA WSAData;
    WSAStartup(0x0101,&WSAData);
#endif

	//Get Local Ip For Fill in all the Sip Message.
	struct hostent * phost;
	char ip[20];
	char hostname[50];


	/*IPV4Addr addr;
	addr.Hostname(wxGetFullHostName());
	HostName = addr.IPAddress();*/

	gethostname(hostname, 50);
	//std::string hs=Scenario::Conv2Std(wxGetFullHostName());
	phost = gethostbyname(hostname);
	char * * names;
	names = phost->h_aliases;
	char * * iplist;
	iplist = phost->h_addr_list;
	while (* iplist)
	{
	  strcpy(ip, inet_ntoa(* (struct in_addr *) * iplist));
	  HostName=wxString(ip, *wxConvCurrent);
	  iplist++;
	  if (HostName != wxT("127.0.0.1"))
	    break; //So far we only take the first one.But keep the code for later Use.
	}


	SetVendorName(_T("wesley.wang"));

	StepSplash(_("Library init..."));
	SttActionDriverInit();
	xmlInitParser();
	osip_init(&osip);
	SetCallBacks(osip);
	StepSplash(_("Create all sockets..."));
	InitOsipSendSock();
	InitGlobalConfig();

	{
		for (int i=0;i<STT_STATISITEM_NUMS;i++){
			AllStatistics[i]=0;
		}
	}


	LIBXML_TEST_VERSION;

	frame = new MyFrame(_("SipTestTool"),
			    wxPoint(50, 50), wxSize(800, 600));
	{
		for (int i=0;i<MAX_SCENARIOS_NUM;i++){
			AllScenariosForm[i] = NULL;
		}
	}
	m_traceForm = new TraceForm(frame, _("Global Trace Form"),
                                    wxPoint(-1, -1), wxSize(-1, -1),
                                    wxDEFAULT_FRAME_STYLE);
	m_traceForm->Show();

	//osipthread = new OsipPollThread(osip);
	//osipthread->Run();
	recvthread = new OsipRecvThread(osip);
	timers = new TimerThread();


	m_ScenariosManager = new ScenariosManager();

	frame->Show(TRUE);
	frame->Maximize(true);

	StepSplash(_("Parse Cmd line..."));
	if (CmdLineParsed){
	    wxString v=wxT("");
	    if (parser.Found(wxT("lastformindex"),&v)){
		long lastFormIndex=0;
		v.ToLong(&lastFormIndex);
		lastformindex=lastFormIndex;
		ScenariosFormSeq = lastFormIndex+1;
	    }
	}

	wxCommandEvent nouse;
	frame->OnNewWindow(nouse);

	bool AutoStart=false;
	int formindex=lastformindex % MAX_SCENARIOS_NUM;
	if (wxGetApp().AllScenariosForm[formindex]){
	    if (CmdLineParsed){
		wxString v;
		if (parser.Found(wxT("term-num"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetTermNum(v);
		}
		if (parser.Found(wxT("scenario"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetSelectScenatio(v);
		}
		if (parser.Found(wxT("call-times"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCallTimers(v);
		}
		if (parser.Found(wxT("call-durtion"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCallDuration(v);
		}
		if (parser.Found(wxT("call-hold"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCallHold(v);
		}
		if (parser.Found(wxT("maxtransinstack"),&v)){
		    v.ToLong(&MaxTransNumInStack);
		}
		if (parser.Found(wxT("call-heavy"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetHeavy(v);
		}
		if (parser.Found(wxT("fixedtest"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCaseStyle(0);
		}
		if (parser.Found(wxT("roundtest"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCaseStyle(1);
		}
		if (parser.Found(wxT("nomd5"))){
		    NoMd5=true;
		}
		if (parser.Found(wxT("randomtest"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetCaseStyle(2);
		}
		if (parser.Found(wxT("finalnever"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetFinalRuleStyle(0);
		}
		if (parser.Found(wxT("finalscefinish"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetFinalRuleStyle(1);
		}
		if (parser.Found(wxT("finalcasefinish"))){
		    wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetFinalRuleStyle(2);
		}
		if (parser.Found(wxT("tracedebug"),&v)){
		  wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetTraceDebug((v==wxT("yes")));
		}
		if (parser.Found(wxT("tracesip"),&v)){
		  wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetTraceSip((v==wxT("yes")));
		}
		if (parser.Found(wxT("traceerror"),&v)){
		  wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetTraceError((v==wxT("yes")));
		}
		if (parser.Found(wxT("stoponfail"),&v)){
		  wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetFailOnStop((v==wxT("yes")));
		}
		if (parser.Found(wxT("redirecttrace"),&v)){
		  redirecttrace=(v==wxT("yes"));
                  if (redirecttrace){
                    printf("All Trace will redirect to log file!\n");
                  }
		}
		if (parser.Found(wxT("safestop"),&v)){
		  wxGetApp().AllScenariosForm[formindex]->m_ScenariosControlPanel->SetSafeStop((v==wxT("yes")));
		}
		if (parser.Found(wxT("daemon"),&v)){
		    wxGetApp().AllScenariosForm[formindex]->Daemon=v;
		    AutoStart=true;
		}
		if (parser.Found(wxT("tracetermstate"),&v)){
		  wxGetApp().frame->gtMenu->Check(Minimal_GLOBAL_SHOW_REGSTATE,(v==wxT("yes")));
		}
		if (parser.Found(wxT("forceport"),&v)){
		    long lv=-1;
		    v.ToLong(&lv);
		    ForcePort=lv;
		}
		parser.Found(wxT("reportpath"),&ReportPath);
	    }
	}

	if (AutoStart){
	    wxCommandEvent nouse;
	    AllScenariosForm[lastformindex % MAX_SCENARIOS_NUM]->OnDoStart(nouse);
	}

	StepSplash(_("All Init Proc Done"));

	return TRUE;
}

extern void CloseAllSocket(void);
int MyApp::OnExit(){

    //CloseAllSocket();

    AllTranses.ClearAllTrans();
    sipQueue.clear();

    osip_release(osip);
    delete(m_ScenariosManager);
    xmlCleanupParser();
#ifdef __WIN32__
    WSACleanup();
#endif
    delete (m_server);
    delete (m_checker);
    return 0;
}

void MyFrame::InitToolBar(wxToolBar* toolBar)
{
    wxBitmap* bitmaps[8];

    bitmaps[0] = new wxBitmap( new_xpm );
    bitmaps[1] = new wxBitmap( open_xpm );
    bitmaps[2] = new wxBitmap( save_xpm );
    bitmaps[3] = new wxBitmap( copy_xpm );
    bitmaps[4] = new wxBitmap( cut_xpm );
    bitmaps[5] = new wxBitmap( paste_xpm );
    bitmaps[6] = new wxBitmap( print_xpm );
    bitmaps[7] = new wxBitmap( help_xpm );

    int width = 24;
    int currentX = 5;

    toolBar->AddTool( MDI_NEW_WINDOW, *(bitmaps[0]), wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _T("New file"));
    currentX += width + 5;
    toolBar->AddTool(1, *bitmaps[1], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Open file"));
    currentX += width + 5;
    toolBar->AddTool(2, *bitmaps[2], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Save file"));
    currentX += width + 5;
    toolBar->AddSeparator();
    toolBar->AddTool(3, *bitmaps[3], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Copy"));
    currentX += width + 5;
    toolBar->AddTool(4, *bitmaps[4], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Cut"));
    currentX += width + 5;
    toolBar->AddTool(5, *bitmaps[5], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Paste"));
    currentX += width + 5;
    toolBar->AddSeparator();
    toolBar->AddTool(6, *bitmaps[6], wxNullBitmap, FALSE, currentX, -1, (wxObject *) NULL, _("Print"));
    currentX += width + 5;
    toolBar->AddSeparator();
    toolBar->AddTool(7, *bitmaps[7], wxNullBitmap, TRUE, currentX, -1, (wxObject *) NULL, _("Help"));

    toolBar->Realize();

    int i;
    for (i = 0; i < 8; i++)
        delete bitmaps[i];
}

MyFrame::MyFrame()
{
  ;
}


MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, long style)
  : wxMDIParentFrame(NULL, -1, title, pos, size, style)
{
    wxMenu *menuFile = new wxMenu;
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(Minimal_About, _("&About...\tF1"), _("Show about dialog"));
    menuFile->Append(Minimal_Close, _("C&lose\tAlt-L"), _("Close the actived child!!"));
    menuFile->Append(Minimal_Quit, _("E&xit\tAlt-X"), _("Quit this program"));

    gtMenu = new wxMenu;
    gtMenu->AppendCheckItem(Minimal_GLOBAL_TRACE_INFO, _("Global Trace Info"), _("Switch Global Info Trace"));
    gtMenu->Check(Minimal_GLOBAL_TRACE_INFO,true);
    gtMenu->AppendCheckItem(Minimal_GLOBAL_TRACE_SIP, _("Global Trace Sip"), _("Switch Global Junk Msg Tracce"));
    gtMenu->AppendSeparator();
    gtMenu->AppendCheckItem(Minimal_GLOBAL_THROW_JUNK_RESPONSE, _("Global Throw Junk Response"), _("Switch Global Throw Junk Response"));
    gtMenu->Check(Minimal_GLOBAL_THROW_JUNK_RESPONSE,true);
    gtMenu->AppendCheckItem(Minimal_GLOBAL_AUTO_100, _("Auto Send 100 Try"), _("Auto Send 100 Try when INVITE comes!"));
    gtMenu->Check(Minimal_GLOBAL_AUTO_100,true);
	
    gtMenu->AppendSeparator();
    gtMenu->AppendCheckItem(Minimal_GLOBAL_SHOW_REGSTATE, _("Show Regist State"), _("Terminal Color Change when Regist State Change"));
    gtMenu->Check(Minimal_GLOBAL_SHOW_REGSTATE,true);

    wxMenu *toolMenu = new wxMenu;
    toolMenu->Append(Minimal_Conf, _("Global C&onfig\tAlt-O"), _("Config this program"));
    toolMenu->Append(Minimal_GLOBAL_TRACE_SET, _("Global &Trace\tAlt-T"), gtMenu,  _("Global Trace Set"));
	/*toolMenu->AppendSeparator();
    wxMenu *langMenu = new wxMenu;
    langMenu->Append(Minimal_GLOBAL_LANGUAGE_CHOOSE_CHINESE, _("Chinese"), _("Switch to chinese language"));
    langMenu->Append(Minimal_GLOBAL_LANGUAGE_CHOOSE_ENGLISH, wxT("English"), _("Switch to english language"));
    toolMenu->Append(wxNewId(), _("Language"), langMenu,  _("Choose Language"));*/


    /*toolMenu->Append(-1, wxT("-"), wxT(""));
    toolMenu->Append(Minimal_Round_Test, _("&Round Test\tAlt-R"), _("Do Round Test"));
    toolMenu->Append(Minimal_Random_Test, _("R&andom Test\tAlt-A"), _("Do Randome Test"));*/


    wxMenu *optMenu = new wxMenu;
    optMenu->Append(Minimal_Clear_Trace, _("C&lear Trace\tAlt-D"), _("Clear Trace Window"));
    optMenu->Append(Minimal_Clear_Transaction, _("C&lear Transaction\tAlt-R"), _("Clear All Sip Transaction"));
    optMenu->Append(Minimal_Clear_Timer, _("C&lear All Timer\tAlt-R"), _("Clear All Timer Record"));
    optMenu->Append(Minimal_Clear_Transaction, _("C&lear All Global Statistic\tAlt-T"), _("Clear All Global Statistic"));
    optMenu->Append(Minimal_Force_Port, _("&Force Port\tAlt-P"), _("Force Change port"));
    optMenu->Append(Minimal_Update_AllCase, _("&Update All Case\tAlt-S"), _("Update All Case"));

    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(menuFile, _("&File"));
    menuBar->Append(optMenu, _("&Operate"));
    menuBar->Append(toolMenu, _("&Tool"));
    menuBar->Append(helpMenu, _("&Help"));

    m_timer= new wxTimer(this, STATUS_BAR_TIMER_ID);
    m_timer->Start(1000);

    SetMenuBar(menuBar);

    CreateToolBar(wxNO_BORDER | wxTB_FLAT | wxTB_HORIZONTAL);
    InitToolBar(GetToolBar());

    //Status Bar to show the app level statistic, include:
    //All Send Msg Num
    //All Recv Msg Num
    CreateStatusBar(STT_STATISITEM_NUMS);
    SetStatusText(_("Welcome to SipTestTool!"));

}

/*
// just some functions to get a slightly deeper stack trace
static void bar(const wxChar *p)
{
    char *pc = 0;
    *pc = *p;

    printf("bar: %s\n", p);
}

void baz(const wxString& s)
{
    printf("baz: %s\n", s.c_str());
}

void foo(int n)
{
    if ( n % 2 )
        baz(wxT("odd"));
    else
        bar(wxT("even"));
	}*/


void MyFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event) )
{

    /*
    // this call is going to crash
    foo(32);
    foo(17);
    return;
    */

	#define MAX_SCENARIOS_FROM_SEQ 20
	for (int i=lastformindex;i<MAX_SCENARIOS_NUM;i++){
		if (!wxGetApp().AllScenariosForm[i % MAX_SCENARIOS_NUM]){
		    ScenariosForm *subframe = new ScenariosForm(ScenariosFormSeq%MAX_SCENARIOS_FROM_SEQ,this, _T("Scenarios Form"),
		                                    wxPoint(-1, -1), wxSize(800, 600),
		                                    wxDEFAULT_FRAME_STYLE);

		    wxString title;
		    title.Printf(_("Scenarios Form %d"),ScenariosFormSeq);
		    ScenariosFormSeq++;

		    subframe->SetTitle(title);
		    subframe->CreateStatusBar();
		    subframe->SetStatusText(title);
			subframe->SetFormIndex(i);
			wxGetApp().AllScenariosForm[i] = subframe;

		    subframe->Show(TRUE);
		    //wxGetApp().frame->Tile();
			return;
		}
	}
	wxLogError(_("Try to close some of no use ScenariosForm for a new one!"));
}

void MyFrame::OnChangeIdent(wxCommandEvent& WXUNUSED(event))
{
	ScenariosForm*form = (ScenariosForm*)wxGetApp().frame->GetActiveChild();

	if (wxGetApp().GetFormIndex(form)>0){
		if (form){
			int ScenariosIndex = form->m_ScenariosControlPanel->GetSelectScenariosIndex();
			if (ScenariosIndex<0){
				wxLogError(_("you should first select one scenarios to Change Identifier!"));
				return;
			}
			else if (ScenariosIndex>(int)wxGetApp().m_ScenariosManager->AllScenarios.size()){
				wxLogError(_("This should never happen,restart the program,if it is still happen,contact the author!"));
				return;
			}
			wxTextEntryDialog dialog(this,
                           _("Please Input your new Identifier\n"),
							_("Please Input one string:"),
                           wxGetApp().m_ScenariosManager->AllScenarios[ScenariosIndex]->GetIdentifier(),
                           wxOK | wxCANCEL);

			if (dialog.ShowModal() == wxID_OK)
			{
				wxGetApp().m_ScenariosManager->AllScenarios[ScenariosIndex]->SetIdentifier(dialog.GetValue());
			}
		}
	}
	else{
		wxLogMessage(_("Not a Valid Form Type!"));
	}
}

void MyFrame::OnLangChinese(wxCommandEvent& WXUNUSED(event)){
    wxGetApp().m_locale.Init(wxLANGUAGE_CHINESE_SIMPLIFIED);
}

void MyFrame::OnLangEnglish(wxCommandEvent& WXUNUSED(event)){
    wxGetApp().m_locale.Init(wxLANGUAGE_ENGLISH);
}

void MyFrame::OnConfig(wxCommandEvent& WXUNUSED(event))
{
  ConfigDialog m_dialog(this,wxGetApp().m_ScenariosManager->DefaultScenario->GetMap());
  m_dialog.Center();
  m_dialog.ShowModal();
}

void MyFrame::OnUpdateAllCase(wxCommandEvent& WXUNUSED(event))
{
    wxMessageDialog dialog(NULL, _("Close All Scenario Form and press return!"),
			   _("Alert"), wxOK|wxCANCEL|wxICON_INFORMATION);

    if (dialog.ShowModal()==wxID_OK){
	delete(wxGetApp().m_ScenariosManager);
	wxGetApp().m_ScenariosManager = new ScenariosManager();
	wxLogMessage(_("Will Take effect in next Scenario Form!!"));
    }
    else{
	return;
    }
}

void MyFrame::OnForcePort(wxCommandEvent& WXUNUSED(event))
{
    long v = wxGetNumberFromUser( _("Enter the port number you want:"),\
                                    _("Port Number:"), _T("Force Port"),\
                                     ForcePort, 0, 65535, this );
    if (v!=-1) ForcePort=v;
}

void MyFrame::OnClearTimer(wxCommandEvent& WXUNUSED(event))
{
    wxGetApp().timers->CancelScenarioTimer(-1);
    //ClearAllTransaction();
}

void MyFrame::OnClearTrans(wxCommandEvent& WXUNUSED(event))
{
  wxGetApp().AllTranses.ClearAllTrans();
}


extern void ClearGlobalStat();
void MyFrame::OnClearStatictic(wxCommandEvent& WXUNUSED(event))
{
  for (int i=0;i<STT_STATISITEM_NUMS;i++){
    wxGetApp().AllStatistics[i]=0;
  }
  ClearGlobalStat();
}


void MyFrame::OnClearTrace(wxCommandEvent& WXUNUSED(event))
{
  wxMDIChildFrame* p=GetActiveChild();
  if (p){
      if (wxT("TRACEFORM") == p->GetName()){
	  ((TraceForm *)p)->m_Text->Clear();
	  ((TraceForm *)p)->m_msgflow->m_msglist.Clear();
	  ((TraceForm *)p)->m_msgflow->Refresh();
      }
  }
}

void MyFrame::OnClose(wxCloseEvent& event)
{
  /*wxMDIChildFrame* p=NULL;
  while (p=GetActiveChild()){
    p->Close();
    }*/
  wxGetApp().ApplicationExit=true;
  event.Skip();

  delete (m_timer);

  wxGetApp().recvthread->Wait();
  delete(wxGetApp().recvthread);

  wxGetApp().timers->Wait();
  delete(wxGetApp().timers);

  //wxGetApp().osipthread->Wait();
  //    wxGetApp().osipthread->Delete();
  //delete(wxGetApp().osipthread);

}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(TRUE);
}

#ifdef NoBuildTag
std::string BuildTag="Not Present in VC6 version";
#else
extern std::string BuildTag;
#endif

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    wxBitmap bitmap;
    if (bitmap.LoadFile(_T("splash.png"), wxBITMAP_TYPE_PNG))
    {
        wxImage image = bitmap.ConvertToImage();
        image.Rescale( bitmap.GetWidth()/2, bitmap.GetHeight()/2 );
        bitmap = wxBitmap(image);
        wxSplashScreen *splash = new wxSplashScreen(bitmap,
            wxSPLASH_CENTRE_ON_PARENT | wxSPLASH_NO_TIMEOUT,
            0, this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
            wxSIMPLE_BORDER|wxSTAY_ON_TOP);
        wxWindow *win = splash->GetSplashWindow();

        wxStaticText *text = new wxStaticText( win, wxID_EXIT, wxString(_("Version:"))+wxT(STT_VERSION), wxPoint(210,23) );
        text->SetBackgroundColour(*wxWHITE);
        text->SetForegroundColour(*wxBLACK);
        wxFont font = text->GetFont();
        font.SetPointSize(2*font.GetPointSize()/3);
        text->SetFont(font);
	wxString buildat=wxString::Format(wxString(_("The Program is build at "))+wxT("%s ")+_("\nUsing %s"),
					  wxString(wxConvUTF8.cMB2WC((const char*)BuildTag.c_str()),*wxConvCurrent).c_str(),
					  wxVERSION_STRING);
        text = new wxStaticText( win, wxID_EXIT, buildat, wxPoint(5,50) );

    }

    /*    wxString msg;
    msg.Printf( wxString(_("This is the About dialog of the minimal sample.\n"))+
                _("Welcome to %s\n\n")+
		_("The Program is build at ")+wxString(wxConvUTF8.cMB2WC((const char*)BuildTag.c_str()),*wxConvCurrent), wxVERSION_STRING);

		wxMessageBox(msg, _T("About Minimal"), wxOK | wxICON_INFORMATION, this);*/
}

ConfigDialog::ConfigDialog(wxWindow *parent, StrStrHash *amap)
             : wxDialog(parent, -1, wxString(_("SipTestTool Configure")))
{

	map=amap;
    wxBoxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);

    m_btnFocused = new wxButton(this, -1, _("OK"));
    wxButton *btnOk = new wxButton(this, wxID_CANCEL, _T("&Cancel"));
    sizerTop->Add(m_btnFocused, 0, wxALIGN_CENTER | wxALL, 5);
    sizerTop->Add(btnOk, 0, wxALIGN_CENTER | wxALL, 5);

	wxFlexGridSizer *sizerConf = new wxFlexGridSizer(2);
	/*wxConfigBase *pConfig = wxConfigBase::Get();
	  pConfig->SetPath(GLOBAL_KEY);*/

	keys.clear();
	for(TxtCtrlArray::iterator iter=values.begin();iter!=values.end();iter++){
		wxTextCtrl*p = (wxTextCtrl*)*iter;
		delete(p);
	}
	values.clear();

	if (map){
		for(StrStrHash::iterator iter = (*map).begin(); iter != (*map).end(); iter++)
	    {
	        wxString key=(*iter).first;
			keys.push_back(key);
			wxTextCtrl *tmpTextCtrl = new wxTextCtrl(this, -1, wxT(""),wxDefaultPosition,wxSize(150,-1));
			tmpTextCtrl->SetValue(iter->second);
			values.push_back(tmpTextCtrl);
			sizerConf->Add(new wxStaticText(this, -1, key+wxT(": ")), 0,
		                  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
			sizerConf->Add(tmpTextCtrl, 1,
		                   wxGROW | wxALIGN_CENTER_VERTICAL);
	    }
	}
	else{
	  /*	long Index;
		wxString key;
		if (pConfig->GetFirstEntry(key,Index)){
			do{
				keys.push_back(key);
				wxTextCtrl *tmpTextCtrl = new wxTextCtrl(this, -1, wxT(""));
				wxString value;
				if (pConfig->Read(key,&value)){
					tmpTextCtrl->SetValue(value);
				}
				values.push_back(tmpTextCtrl);
				sizerConf->Add(new wxStaticText(this, -1, key+wxT(": ")), 0,
			                  wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
				sizerConf->Add(tmpTextCtrl, 1,
			                   wxGROW | wxALIGN_CENTER_VERTICAL);
			}
			while (pConfig->GetNextEntry(key,Index));
			}*/
	}

	wxSizer *sizerV = new wxBoxSizer(wxVERTICAL);
	sizerV->Add(sizerConf, 1, wxALL | wxALIGN_RIGHT, 5);
	sizerV->Add(sizerTop, 0, wxALL | wxALIGN_RIGHT, 5);

    SetAutoLayout(TRUE);
    SetSizer(sizerV );

    sizerV->SetSizeHints(this);
    sizerV->Fit(this);

    m_btnFocused->SetFocus();
    m_btnFocused->SetDefault();
}

void ConfigDialog::OnButton(wxCommandEvent& event)
{
    if ( event.GetEventObject() == m_btnFocused )
    {
		if (map){
			for (size_t i=0;i<keys.size();i++){
				wxString NewValue = values[i]->GetValue();
				(*map)[keys[i]] = NewValue;
			}
		}
		else{
		  /*wxConfigBase *pConfig = wxConfigBase::Get();
			pConfig->SetPath(Path);
			for (size_t i=0;i<keys.size();i++){
				wxString NewValue = values[i]->GetValue();
				if (pConfig->Read(keys[i]) != NewValue){
					pConfig->Write(keys[i],NewValue);
				}
			}
			pConfig->Flush();*/
		}
		this->Hide();
    }
    else
    {
        event.Skip();
    }
}

#ifdef WIN32
wxFileOutputStream mylogfile(wxT("SipTestTool.log"));
#else
wxFileOutputStream mylogfile(wxT("/tmp/SipTestTool.log"));
#endif
void MyApp::DoLog(const wxString& s){
  std::string ns=Scenario::Conv2Std(s);
  mylogfile.Write(ns.c_str(),ns.size());
  //logf.Flush();
}

void MyApp::StepSplash(const wxString& info){
    static int total=0;
    total++;
    if (splashgauge){
	splashgauge->SetValue(total);
    }
    if (splashtext){
	splashtext->SetLabel(info);
    }
    wxYield();
}

void MyApp::OnFatalException()
{
    //GenerateReport(wxDebugReport::Context_Exception);
}

void MyApp::StopAndExit(){
    wxLogNull logNull;
    frame->StopTimer();
    for (int i=0;i<MAX_SCENARIOS_NUM;i++){
	if (AllScenariosForm[i] && (AllScenariosForm[i]->GetScenarioControl())){
	    wxCommandEvent ScenarioExitEvt(wxEVT_SCENARIO_EXIT);
	    AllScenariosForm[i]->ProcessEvent(ScenarioExitEvt);
	    //wxPostEvent(AllScenariosForm[i]->GetScenarioControl()->GetEvtHandler(), ScenarioExitEvt);
	}
    }
    frame->Close();
}

/*void MyApp::GenerateReport(wxDebugReport::Context ctx)
{
    wxDebugReportCompress *report = new MyDebugReport;
    if (report->IsOk()){
	// add all standard files: currently this means just a minidump and an
	// XML file with system info and stack trace
	report->AddAll(ctx);

	// calling Show() is not mandatory, but is more polite
	if ( wxDebugReportPreviewStd().Show(*report) )
	    {
		if ( report->Process() )
		    {
#ifndef WIN32
			wxMessageOutputMessageBox out;
			out.Printf(_("Please email the coredump file %s to cnwesleywang@gmail.com\nthanks for your help!"),
				   ((MyDebugReport*)report)->GetCompressedFileName().c_str());
#endif
		    }
	    }
    }
    //else: user cancelled the report

    delete report;
}*/

wxConnectionBase *stServer::OnAcceptConnection(const wxString& topic)
{
    if (topic.Lower() == wxT("siptesttool"))
    {
        wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
        while (node)
        {
            wxDialog* dialog = wxDynamicCast(node->GetData(), wxDialog);
            if (dialog && dialog->IsModal())
            {
                return false;
            }
            node = node->GetNext();
        }
        return new stConnection();
    }
    else{
        return NULL;
    }
}

bool stConnection::OnExecute(const wxString& WXUNUSED(topic),
                             wxChar *data,
                             int WXUNUSED(size),
                             wxIPCFormat WXUNUSED(format))
{
    wxString adata(data);
    if (adata==wxT("stopandexit")){
	wxGetApp().StopAndExit();
    }
    return true;
}


